<template>
  <div 
    ref="containerRef"
    class="swipeable-tab-container"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
    @touchcancel="handleTouchCancel"
  >
    <div 
      class="swipeable-tab-wrapper"
      :style="{
        transform: `translateX(${translateX}px)`,
        transition: transitionEnabled ? 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)' : 'none'
      }"
    >
      <div
        v-for="(tab, index) in tabs"
        :key="tab.value"
        class="swipeable-tab-pane"
        :class="{ 'swipeable-tab-pane--active': modelValue === tab.value }"
      >
        <slot :name="`tab-${tab.value}`" :tab="tab" :index="index">
          <slot name="default" :tab="tab" :index="index"></slot>
        </slot>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'

export interface TabItem {
  label: string
  value: string | number
}

interface Props {
  tabs: TabItem[]
  modelValue?: string | number
  // 滑动阈值（像素）
  swipeThreshold?: number
  // 快速滑动阈值（毫秒）
  fastSwipeThreshold?: number
}

interface Emits {
  (e: 'update:modelValue', value: string | number): void
  (e: 'tab-change', value: string | number): void
}

const props = withDefaults(defineProps<Props>(), {
  swipeThreshold: 50,
  fastSwipeThreshold: 300
})

const emit = defineEmits<Emits>()

// 触摸相关状态
const touchStartX = ref(0)
const touchStartY = ref(0)
const touchStartTime = ref(0)
const currentTranslateX = ref(0)
const isSwiping = ref(false)
const transitionEnabled = ref(true)

// 容器宽度
const containerWidth = ref(0)

// 当前活动的 tab 索引
const currentIndex = computed(() => {
  return props.tabs.findIndex(tab => tab.value === props.modelValue)
})

// 计算 translateX 值
const translateX = computed(() => {
  if (isSwiping.value) {
    // 滑动中，实时跟随手指
    return currentTranslateX.value - (currentIndex.value * containerWidth.value)
  }
  // 静止状态，根据当前索引计算位置
  return -(currentIndex.value * containerWidth.value)
})

// 监听 modelValue 变化，重置位置
watch(() => props.modelValue, () => {
  if (!isSwiping.value) {
    currentTranslateX.value = 0
  }
})

// 获取容器宽度
const containerRef = ref<HTMLElement | null>(null)
const updateContainerWidth = () => {
  if (containerRef.value) {
    containerWidth.value = containerRef.value.clientWidth
  }
}

onMounted(() => {
  updateContainerWidth()
  window.addEventListener('resize', updateContainerWidth)
})

// 触摸开始
const handleTouchStart = (e: TouchEvent) => {
  if (props.tabs.length <= 1) return
  
  const touch = e.touches[0]
  if (touch) {
    touchStartX.value = touch.clientX
    touchStartY.value = touch.clientY
    touchStartTime.value = Date.now()
    isSwiping.value = false
    currentTranslateX.value = 0
    transitionEnabled.value = false
  }
}

// 触摸移动
const handleTouchMove = (e: TouchEvent) => {
  if (props.tabs.length <= 1) return
  if (!touchStartX.value || !touchStartY.value) return
  
  const touch = e.touches[0]
  if (!touch) return
  
  const deltaX = touch.clientX - touchStartX.value
  const deltaY = Math.abs(touch.clientY - touchStartY.value)
  const absDeltaX = Math.abs(deltaX)
  
  // 判断是否为横向滑动（横向滑动距离大于纵向滑动距离）
  // 在第一次检测到横向滑动时，尽早阻止默认行为
  // 只有当横向滑动明显大于纵向滑动时才阻止纵向滚动
  if (absDeltaX > deltaY * 1.5 && absDeltaX > 20) {
    // 标记为滑动状态
    if (!isSwiping.value) {
      isSwiping.value = true
    }
    
    // 只在事件可取消时才阻止默认行为
    // 避免在页面已经滚动时尝试取消不可取消的事件
    if (e.cancelable) {
      e.preventDefault()
    }
    
    // 计算当前应该的偏移量
    let targetTranslateX = deltaX
    
    // 边界限制：第一页不能向右滑动，最后一页不能向左滑动
    const minTranslateX = currentIndex.value === 0 ? 0 : -(containerWidth.value * (props.tabs.length - 1))
    const maxTranslateX = currentIndex.value === props.tabs.length - 1 ? 0 : -(containerWidth.value * (props.tabs.length - 1))
    
    // 添加弹性效果：超出边界时，阻力增加
    if (currentIndex.value === 0 && deltaX > 0) {
      // 第一页向右滑动，添加阻力
      targetTranslateX = deltaX * 0.3
    } else if (currentIndex.value === props.tabs.length - 1 && deltaX < 0) {
      // 最后一页向左滑动，添加阻力
      targetTranslateX = deltaX * 0.3
    }
    
    currentTranslateX.value = targetTranslateX
  }
}

// 触摸结束
const handleTouchEnd = (e: TouchEvent) => {
  if (!isSwiping.value || !touchStartX.value) {
    resetTouchState()
    return
  }
  
  const touch = e.changedTouches[0]
  if (!touch) {
    resetTouchState()
    return
  }
  
  const deltaX = touch.clientX - touchStartX.value
  const deltaY = Math.abs(touch.clientY - touchStartY.value)
  const absDeltaX = Math.abs(deltaX)
  const deltaTime = Date.now() - touchStartTime.value
  
  // 判断是否满足切换条件
  const isFastSwipe = deltaTime < props.fastSwipeThreshold
  const minSwipeDistance = isFastSwipe ? props.swipeThreshold * 0.6 : props.swipeThreshold
  const shouldSwipe = absDeltaX > deltaY && absDeltaX > minSwipeDistance
  
  if (shouldSwipe) {
    let newIndex = currentIndex.value
    
    if (deltaX > 0) {
      // 向右滑动，切换到上一个
      newIndex = Math.max(0, currentIndex.value - 1)
    } else {
      // 向左滑动，切换到下一个
      newIndex = Math.min(props.tabs.length - 1, currentIndex.value + 1)
    }
    
    // 切换 tab
    if (newIndex !== currentIndex.value && newIndex >= 0 && newIndex < props.tabs.length) {
      const newTab = props.tabs[newIndex]
      if (newTab) {
        emit('update:modelValue', newTab.value)
        emit('tab-change', newTab.value)
      }
    }
  }
  
  // 重置状态并启用过渡动画
  transitionEnabled.value = true
  resetTouchState()
}

// 触摸取消
const handleTouchCancel = () => {
  resetTouchState()
}

// 重置触摸状态
const resetTouchState = () => {
  touchStartX.value = 0
  touchStartY.value = 0
  touchStartTime.value = 0
  isSwiping.value = false
  currentTranslateX.value = 0
  transitionEnabled.value = true
}
</script>

<style scoped>
.swipeable-tab-container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* 允许纵向滚动，阻止横向滚动（由我们控制） */
  touch-action: pan-y pinch-zoom;
}

.swipeable-tab-wrapper {
  display: flex;
  width: 100%;
  height: 100%;
  will-change: transform; /* 优化性能 */
}

.swipeable-tab-pane {
  flex-shrink: 0;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  /* 隐藏滚动条但保持滚动功能 */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE 和 Edge */
}

/* Chrome、Safari 和 Opera */
.swipeable-tab-pane::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

.swipeable-tab-pane--active {
  /* 可以添加激活状态的样式 */
}
</style>

